package com.tsfyun.scm.security.config;

import com.alibaba.fastjson.JSONObject;
import com.tsfyun.common.base.constant.LoginConstant;
import com.tsfyun.common.base.constant.UserAuthoritiesConstant;
import com.tsfyun.common.base.dto.Result;
import com.tsfyun.common.base.security.AuthLoginUtil;
import com.tsfyun.common.base.security.LoginVO;
import com.tsfyun.common.base.security.TokenVO;
import com.tsfyun.common.base.util.ResultUtil;
import com.tsfyun.common.base.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Objects;

@Slf4j
@Component
public class TokenAuthorizationFilter extends OncePerRequestFilter {

    private final StringRedisUtils stringRedisUtils;

    private AntPathMatcher pathMatcher = new AntPathMatcher();

    public TokenAuthorizationFilter(StringRedisUtils stringRedisUtils) {
        this.stringRedisUtils = stringRedisUtils;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token;
        //此处针对websocket处理，由于token是放在路径中的参数，无法放在请求头中，以及获取租户编码处理
        if (pathMatcher.match("/websocket", httpServletRequest.getRequestURI()) || pathMatcher.match("/sock-js", httpServletRequest.getRequestURI())) {
            token = httpServletRequest.getParameter("token");
        } else {
            token = httpServletRequest.getHeader("token");
        }
        if(StringUtils.isNotEmpty(token) && Objects.isNull(SecurityContextHolder.getContext().getAuthentication())) {
            String tokenInfo = "";
            try {
                tokenInfo = stringRedisUtils.getToString(LoginConstant.TOKEN + token);
            } catch (Exception e) {
                ResultUtil.errorBack(httpServletResponse,new Result("0", "系统异常，请稍后再试"));
                return;
            }
            if(StringUtils.isNotEmpty(tokenInfo)) {
                TokenVO tokenVO = JSONObject.parseObject(tokenInfo,TokenVO.class);
                String authPerson = stringRedisUtils.getToString(LoginConstant.AUTH + tokenVO.getPersonId());
                //此处偶现序列化出错，如果出错则强制退出暂时
                LoginVO loginVO;
                try {
                    loginVO = JSONObject.parseObject(authPerson, LoginVO.class);
                } catch (Exception e) {
                    log.error(String.format("登录人员信息【%s】序列化异常",authPerson),e);
                    loginVO = null;
                    stringRedisUtils.remove(LoginConstant.AUTH + tokenVO.getPersonId());
                }
                if(Objects.nonNull(loginVO)) {
                    //此处把该token的使用权限设置进来以便需要对某些接口做权限控制（仅限于需要登录的接口）
                    Collection<SimpleGrantedAuthority> grantedAuthorities = (Collection<SimpleGrantedAuthority>) AuthLoginUtil.getAuthorities(loginVO.getSysRoles());
                    String loginTokenRoleType = tokenVO.getRoleType();
                    if(StringUtils.isNotEmpty(loginTokenRoleType)) {
                        SimpleGrantedAuthority loginRoleTypeAuth = new SimpleGrantedAuthority(StringUtils.null2EmptyWithTrim(UserAuthoritiesConstant.ROLE_TYPE_PREFIX.concat(loginTokenRoleType)));
                        grantedAuthorities.add(loginRoleTypeAuth);
                    }
                    UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(loginVO, tokenVO,grantedAuthorities);
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

}
